這份合約是參考Building a To-do list with EOS而來。
原本就已經是舊的寫法。這次重寫,連原本使用的v1.4.1
使用的方式,有不少也變了。
除了之前提到的,不再需要EOSIO_DISPATCH()
(原本沒寫的話,ABI會生成錯誤)。
現在eosio_assert
的使用,要改成check
。而原本的eosio_assert
變得非常的長eosio::internal_use_do_not_use::eosio_assert
。他被放到了一個蠻深的地方(建議不要使用了)。
這次看原始碼,才知道這個eosio_assert
函式有些特殊。不過,不是會編譯成WASM嗎?
(我只挖到新版本的位置,舊版本的目前要挖有些困難...)
首先,先看看標頭檔:
include/todo.hpp
#include <eosio/eosio.hpp>
using namespace std;
using namespace eosio;
CONTRACT todo : public contract {
public:
using contract::contract;
/*
ACTION create_list(name owner, string list_name);
ACTION rename_list(name owner, uint64_t id, string new_name);
ACTION delete_list(name owner, uint64_t id);
ACTION new_task(uint64_t list_id, string tast_content);
ACTION update_task(uint64_t list_id, string task_id, string new_status);
ACTION delete_task(uint64_t list_id, string task_id, string new_status);
*/
ACTION create(name owner, string task);
ACTION update(uint64_t id, string new_status);
ACTION remove(uint64_t id);
private:
TABLE task {
uint64_t id;
name owner;
string task;
string status;
auto primary_key() const { return id; }
};
typedef multi_index<"tasks"_n, task> tasks_table;
};
雖然我很想做一個,可以多個人建立多個待辦清單;在每個清單上,有各自的任務;任務主要有任務內容與狀態。不過這樣合約太過複雜了,不適合作為一個入門的範例,所以決定維持原本,只有建立任務、更新任務狀態和刪除任務,僅這些活動的合約。
然後來看看實現:
src/todo.cpp
#include <todo.hpp>
ACTION todo::create(name owner, string task){
require_auth(owner);
tasks_table tasks(_self, _self.value);
auto id = tasks.available_primary_key();
tasks.emplace(owner, [&](auto& new_task) {
new_task.id = id;
new_task.task = task;
new_task.owner = owner;
new_task.status = "TODO";
});
eosio::print("task#", id, " created");
}
ACTION todo::update(uint64_t id, string new_status){
tasks_table tasks(_self, _self.value);
auto task_lookup = tasks.find(id);
eosio::check(task_lookup != tasks.end(), "Todo does not exist");
//eosio::internal_use_do_not_use::eosio_assert(task_lookup != tasks.end(), "Todo does not exist");
name owner = task_lookup->owner;
require_auth(owner);
tasks.modify(task_lookup, eosio::same_payer, [&](auto& row) {
row.status = new_status;
});
eosio::print("todo#", id, " marked as complete");
}
ACTION todo::remove(uint64_t id){
tasks_table tasks(_self, _self.value);
auto todo_lookup = tasks.find(id);
tasks.erase(todo_lookup);
eosio::print("todo#", id, " destroyed");
}
//EOSIO_DISPATCH(todo, (new_task)(update_task)(delete_task))
關於資料的儲存型態TABLE
,基本上應該不難理解。複雜的在於multi_index
,不過我想在這個範例還足夠好理解,佔不多做解釋,有問題可以留言問。
對於建立任務:
透過tasks.emplace()
儲存新任務到合約裡面。比較少人會去注意的是,還得決定由誰支付使用的記憶體空間(記得EOS的三大資源)?這裡,我們而外指定一個Owner,當然也可以由智能合約本身負擔。
另外,其實可以建立多個TABLE
。tasks_table tasks(_self, _self.value);
使用時,第二個參數是scope
。不同scope
的資料不會互相影響,可以平行處理。不過這裡簡單使用合約本身謹此一個TABLE
。
對於更新任務:
透過tasks.find(id);
找到要更新的任務;tasks.modify()
修改任務。在這部份,還需要驗證身份require_auth(owner);
,避免被不當修改。
刪除任務
最後,與更新合約做一個對照,故意不驗證身份,讓所有任都可以去刪除任務(tasks.erase();
)。
OK,嘗試看看: